package com_operation

import (
	"PackingScanApp/db_mysql_server"
	"PackingScanApp/db_sqlserver_server"
	"PackingScanApp/json_conf_get"
	"PackingScanApp/models"
	"PackingScanApp/view_body"
	"errors"
	"time"

	"strings"

	"PackingScanApp/util"
	"fmt"

	// "runtime"
	"strconv"

	//"mahonia"
	// "github.com/axgle/mahonia"

	"github.com/tarm/serial" //串口包
)

var (
	now_packing_data = models.Now_packing_data{}
)

//初始化函数
func init() {
	var now_packaging_status models.Now_packaging_status
	var barcode_packinglists []models.Barcodepackinglist

	//包装数据初始化
	if err := db_server_mysql.SelectNow_packing_data(&now_packing_data); err != nil {
		runError(errors.New("初始化当前包装人员数据失败！"))
	}
	//包装状态初始化
	if err := db_server_mysql.SelectNow_packaging_status(&now_packaging_status); err != nil {
		runError(errors.New("初始化当前包装状态数据失败！"))
	}
	if now_packaging_status.Packid != 0 {
		if err_nps := db_server_mysql.SelectBarcodepackinglist_packid(&barcode_packinglists, now_packaging_status.Packid); err_nps != nil {
			runError(errors.New("初始化时查询未包装完的列表时失败"))
		}
	}

	if now_packaging_status.Packid != 0 && now_packaging_status.Packnum != 0 {
		//刷新包装界面
		view_body.GetHtmlBody().SystemMsg = `<b style="color:red">--</b>`
		view_body.GetHtmlBody().PackingProducts = now_packing_data.P_name
		view_body.GetHtmlBody().PackingInputUser = now_packing_data.Inputuser
		view_body.GetHtmlBody().Line_mark = now_packing_data.Line_mark
		view_body.GetHtmlBody().Line_mark_note = now_packing_data.Line_mark_note

		view_body.GetHtmlBody().FBillNo = now_packaging_status.Fbillno
		view_body.GetHtmlBody().FNumber = now_packaging_status.Fnumber
		view_body.GetHtmlBody().PackingNumHTML = strconv.Itoa(now_packaging_status.Sum_packnum)
		view_body.GetHtmlBody().NowPackingNumHTML = strconv.Itoa(now_packaging_status.Packnum)

		for _, vals := range barcode_packinglists {
			view_body.GetHtmlBody().PackingListHTML = `<tr>
			                  <td>` + vals.Barcode + `</td>
			                  <td>` + vals.Inputtime + `</td>
			                </tr>` + view_body.GetHtmlBody().PackingListHTML
		}

		view_body.GetBodyCChan().DoShowBody <- 1
	} else if now_packaging_status.Fbillno != "0" {
		//刷新包装界面
		view_body.GetHtmlBody().SystemMsg = `<b style="color:red">--</b>`
		view_body.GetHtmlBody().PackingProducts = now_packing_data.P_name
		view_body.GetHtmlBody().PackingInputUser = now_packing_data.Inputuser
		view_body.GetHtmlBody().Line_mark = now_packing_data.Line_mark
		view_body.GetHtmlBody().Line_mark_note = now_packing_data.Line_mark_note

		view_body.GetHtmlBody().FBillNo = now_packaging_status.Fbillno
		view_body.GetHtmlBody().FNumber = now_packaging_status.Fnumber
		view_body.GetHtmlBody().PackingNumHTML = strconv.Itoa(now_packaging_status.Sum_packnum)
		view_body.GetHtmlBody().NowPackingNumHTML = strconv.Itoa(now_packaging_status.Packnum)
	}
}

//取得当前包装及人员信息
func GetNowPackingData() *models.Now_packing_data {
	return &now_packing_data
}

//错误处理函数！
func runError(err interface{}) {
	//util.File_write_string("log_file", "errLog-"+util.GetNowTime("yyyy-MM"), "\r\n"+fmt.Sprintf("%s", err)+util.GetNowTime("yyyy-MM-dd hh-mm-ss"))
	view_body.GetHtmlBody().SystemMsg = `<b style="color:red;">` + fmt.Sprintf("%s", err) + "</b>"
	view_body.GetBodyCChan().DoShowBody <- 1
	//调用声音
	//go util.Play_sound()
	//记录日志
	err_log := models.ErrLog{
		Errmsg:    fmt.Sprintf("%s", err),
		Date_time: util.GetNowTime("yyyy-MM-dd hh-mm-ss"),
	}
	db_server_mysql.InsertErrLog(&err_log)
}

//新建一个Com监听器
func NewCOMMonitor() {
	defer func() {
		if err := recover(); err != nil {
			runError(err)
		}
	}() //--
	ch := make(chan byte)

	//与计算机主机通讯，使用高速波特率115200；默认常规波特率为9600
	//&serial.Config{Name: "COM3", Baud: 9600}, //
	c := []*serial.Config{}

	var cominfos []models.ComInfo

	if err := db_server_mysql.SelectCOMInfo(&cominfos); err == nil {
		for _, value := range cominfos {
			c = append(c, &serial.Config{Name: value.Com_str, Baud: value.Baudrate})
		}
	} else {
		panic(err)
	}

	//初始化串口
	for _, value_c := range c {
		/**
		*	源代码更改过：erial.OpenPort().openPort().setCommState()
		*	params.flags[1] = 0x10 // Assert DSR
		 */
		if s, err1 := serial.OpenPort(value_c); err1 == nil {
			go readCom(s) //打开扫码枪读监听
		} else {
			panic(errors.New("有串口扫码枪初始化失败！"))
		}
	}

	time.Sleep(time.Second * 3)
	view_body.GetHtmlBody().SystemMsg = `<b>所有扫码枪监听正常</b>`
	view_body.GetBodyCChan().DoShowBody <- 1

	<-ch
}

//读取扫码枪
func readCom(s *serial.Port) {
	//读数据
	buf := make([]byte, 24)
	var tmpstr string = ""
	for {
		n, err := s.Read(buf)
		if err != nil {
			runError(err)
		}
		tmpstr += fmt.Sprintf("%s", string(buf[:n]))
		if strings.LastIndex(tmpstr, "\n") > 0 || strings.LastIndex(tmpstr, "\r\n") > 0 || strings.LastIndex(tmpstr, "\t") > 0 {
			tmpstr = strings.Replace(tmpstr, " ", "", -1)  //去掉空格
			tmpstr = strings.Replace(tmpstr, "\r", "", -1) //去掉回车
			tmpstr = strings.Replace(tmpstr, "\n", "", -1) //去掉换行
			tmpstr = strings.Replace(tmpstr, "\t", "", -1) //去掉制表符

			go doBusiness(tmpstr) //执行业务操作
			tmpstr = ""

		}
	}
}

//执行业务操作
func doBusiness(scan_str string) {
	defer func() {
		if err := recover(); err != nil {
			runError(err)
		}
	}() //--
	//先将扫码枪内容刷新到页面
	view_body.GetHtmlBody().NowScanData = scan_str
	view_body.GetBodyCChan().DoShowBody <- 1

	//------
	//当前日包装数量 序号
	var today_sum models.Today_sum
	if err_td := db_server_mysql.SelectTodaySum(&today_sum, util.GetNowTime("yyyy-MM-dd")); err_td != nil {
		if strings.LastIndex(fmt.Sprintf("%s", err_td), "no row found") >= 0 {
			today_sum_insert := models.Today_sum{
				Num_sum: 1,
				Time:    util.GetNowTime("yyyy-MM-dd"),
			}
			if _, err_i := db_server_mysql.InsertTodaySum(&today_sum_insert); err_i == nil {
				if err_td2 := db_server_mysql.SelectTodaySum(&today_sum, util.GetNowTime("yyyy-MM-dd")); err_td2 != nil {
					panic(errors.New("查询包装数量错误！"))
				}
			} else {
				panic(errors.New("插入当日包装数量错误！"))
			}
		} else {
			panic(errors.New("查询错误！"))
		}
	}

	//------
	//当前包装箱状态
	var now_packaging_status models.Now_packaging_status
	if err := db_server_mysql.SelectNow_packaging_status(&now_packaging_status); err != nil {
		panic(errors.New("查询正在包装状态错误！"))
	}
	//--当前包装箱--
	barcodepacking := models.Barcodepacking{
		Packno:    util.GetNowTime("yyyyMMdd")[2:] + now_packing_data.Line_mark + fmt.Sprintf("%04d", today_sum.Num_sum), //包装箱序列号
		Inputtime: util.GetNowTime("yyyy-MM-dd hh-mm-ss"),
		Inputuser: now_packing_data.Inputuser,
		Fbillno:   now_packaging_status.Fbillno,
		Fnumber:   now_packaging_status.Fnumber,
	}
	//当前包装列表
	bpackinglist := models.Barcodepackinglist{
		Packid:    now_packaging_status.Packid,
		Barcode:   scan_str,
		Inputtime: util.GetNowTime("yyyy-MM-dd hh-mm-ss"),
	}

	//----barcodepacking.Packno
	if now_packaging_status.Fbillno == "0" || now_packaging_status.Fnumber == "0" {
		//panic(errors.New("-------------"))
		if strings.LastIndex(scan_str, "function:finish") >= 0 {
			panic(errors.New("当前还未产品录入！"))
		}
		updateFbillNo_fnum(scan_str, 0)
	} else {
		//--------
		//最先检测已包装数量是否等于需要包装数量
		if now_packaging_status.Packnum > 0 && now_packaging_status.Packnum == now_packaging_status.Sum_packnum {
			var barcodepacking models.Barcodepacking
			//查询是否打印
			if err := db_server_mysql.SelectBarcodepacking_isprint(&barcodepacking, now_packaging_status.Packid); err == nil {
				//没有打印，更新打印状态,并调用打印
				print_data := models.PrintData{
					Part_number:      now_packaging_status.Fnumber,
					Part_description: now_packaging_status.Fname,
					Lot_number:       now_packaging_status.Fbillno,
					Batch_number:     barcodepacking.Packno,
					Quantity:         strconv.Itoa(now_packaging_status.Packnum),
					Date_s:           util.GetNowTime("yyyy-MM-dd"),
					Code_base64_str:  util.GetQrcodeBase64(barcodepacking.Packno),
					Print_type:       0,
					Address_s:        getAddress_s(),
				}

				if e_print := db_server_mysql.UpdatePrint_s(util.GetNowTime("yyyy-MM-dd hh-mm-ss"), now_packaging_status.Packid, &print_data, &today_sum); e_print == nil {
					go util.RunPrintBat()
					resetPackingData(now_packaging_status.Packid)
				}
			} else {
				if strings.LastIndex(fmt.Sprintf("%s", err), "no row found") >= 0 {
					//根据序列号查询包装箱
					var bpacking models.Barcodepacking
					if err_no := db_server_mysql.SelectBarcodepacking(&bpacking, scan_str); err_no == nil {
						resetPackingData(now_packaging_status.Packid)
					} else {
						panic(errors.New("已达最大包装数量，请扫装箱标签完成装箱！"))
					}
				} else {
					panic(errors.New("查询是否打印错误！"))
				}
			}
		} else if now_packaging_status.Packnum == 0 { //包装数量为0
			if checkIsBarcode(&now_packing_data, scan_str) { //有条码
				replaceView_barcode(scan_str, 0, now_packaging_status.Packnum+1, &barcodepacking, &bpackinglist) //刷新页面并更新数据库
			} else { //没有查到条码
				updateFbillNo_fnum(scan_str, 1) //再次检测更新一下流程卡号
			}
		} else if now_packaging_status.Packnum > 0 && now_packaging_status.Packnum < now_packaging_status.Sum_packnum {
			//是否为尾箱扫码
			if strings.LastIndex(scan_str, "function:finish") >= 0 {
				//调用打印
				var barcodepacking models.Barcodepacking
				//查询是否打印
				if err := db_server_mysql.SelectBarcodepacking_isprint(&barcodepacking, now_packaging_status.Packid); err == nil {
					//没有打印，更新打印状态,并调用打印；并重置包装状态
					print_data := models.PrintData{
						Part_number:      now_packaging_status.Fnumber,
						Part_description: now_packaging_status.Fname,
						Lot_number:       now_packaging_status.Fbillno,
						Batch_number:     barcodepacking.Packno,
						Quantity:         strconv.Itoa(now_packaging_status.Packnum),
						Date_s:           util.GetNowTime("yyyy-MM-dd"),
						Code_base64_str:  util.GetQrcodeBase64(barcodepacking.Packno),
						Print_type:       0,
						Address_s:        getAddress_s(),
					}

					if e_print := db_server_mysql.UpdatePrint_s(util.GetNowTime("yyyy-MM-dd hh-mm-ss"), now_packaging_status.Packid, &print_data, &today_sum); e_print == nil {
						resetPackingData(now_packaging_status.Packid) //重置界面
						util.RunPrintBat()
					}
				} else {
					panic(errors.New("严重逻辑错误！"))
				}
				//结束
				return
			}

			//检测是否扫过
			var bplist models.Barcodepackinglist
			if e1 := db_server_mysql.SelectBarcodepackinglist_barcode(&bplist, scan_str); e1 == nil {
				if len(bplist.Barcode) > 0 {
					panic(errors.New("该条码已扫过！如果非操作重复！此码为重码！"))
				}
			} else {
				if strings.LastIndex(fmt.Sprintf("%s", e1), "no row found") >= 0 {
					//什么也不做
				} else {
					panic(errors.New("检查重码时错误！"))
				}
			}
			//
			if checkIsBarcode(&now_packing_data, scan_str) { //有条码
				replaceView_barcode(scan_str, 1, now_packaging_status.Packnum+1, &barcodepacking, &bpackinglist) //刷新页面并更新数据库
			} else { //没有查到条码
				panic(errors.New("当前未达到装箱数量，此条码未找到！"))
			}
		}

	}
}

//更新包装状态数据表和重置包装界面
func resetPackingData(packing_id int64) {
	//将界面重置
	n_p_status := models.Now_packaging_status{
		Packid:      0,
		Packnum:     0,
		Fbillno:     "0",
		Fnumber:     "0",
		Sum_packnum: 0,
		Fname:       "0",
	}
	// if e_np := db_server_mysql.UpdateNowPackagingStatus(&n_p_status); e_np != nil {
	// 	panic(errors.New("重置包装状态错误！"))
	// }

	if e_np := db_server_mysql.ResetNowPackagingStatus_D(&n_p_status, packing_id); e_np != nil {
		panic(errors.New("重置包装状态错误！"))
	}

	view_body.GetHtmlBody().SystemMsg = `<b style="color:red">--</b>`
	view_body.GetHtmlBody().PackingProducts = `--`
	view_body.GetHtmlBody().PackingInputUser = `--`
	view_body.GetHtmlBody().FBillNo = `--`
	view_body.GetHtmlBody().FNumber = `--`
	view_body.GetHtmlBody().PackingNumHTML = `--`
	view_body.GetHtmlBody().NowPackingNumHTML = `--`
	view_body.GetHtmlBody().NowScanData = `--`
	view_body.GetHtmlBody().Line_mark = `--`
	view_body.GetHtmlBody().Line_mark_note = `--`
	view_body.GetHtmlBody().PackingListHTML = ``

	view_body.GetBodyCChan().DoShowBody <- 1
}

//检查是否有产品条码,返回 true 有条码
func checkIsBarcode(now_packing_data *models.Now_packing_data, scan_str string) bool {
	ret_bool := true
	is_barcode := 0
	if now_packing_data.P_type == 1 || now_packing_data.P_type == 2 {
		is_barcode = db_server_sqlserver.SelectBarcodeParmater_Num(scan_str)
	}
	if now_packing_data.P_type == 3 {
		if num, eee := db_server_mysql.SelectProduct_Count(scan_str); eee == nil {
			is_barcode = num
		} else {
			panic(errors.New("查询40服务器产品错误！"))
		}
	}
	if now_packing_data.P_type == 4 {
		is_barcode = db_server_sqlserver.SelectBarcodeParmaterLBB_Num(scan_str)
	}

	if is_barcode == 0 {
		ret_bool = false
	}
	return ret_bool
}

//更新流程卡物料信息
func updateFbillNo_fnum(scan_str string, type_s int) {

	iCOM_Data := db_server_sqlserver.SelectICOM_Data(scan_str)

	if len(iCOM_Data.Fbillno) == 0 {
		if type_s == 0 {
			panic(errors.New("没查到流程卡及物料信息！"))
		} else {
			panic(errors.New("当前没有扫条码，有流程卡信息，没查到新的流程卡及物料信息！也没有查询到条码信息！"))
		}

	} else {
		if iCOM_Data.Sumnumber == 0 {
			panic(errors.New("该物料的包装数量为0！"))
		} else {
			if err_up := db_server_mysql.UpdateNowPackagingStatus_fbillno_fnumber_sumPacknum(&iCOM_Data); err_up == nil {

				//刷新页面内容
				view_body.GetHtmlBody().FBillNo = iCOM_Data.Fbillno
				view_body.GetHtmlBody().FNumber = iCOM_Data.Fnumber
				view_body.GetHtmlBody().PackingNumHTML = strconv.Itoa(iCOM_Data.Sumnumber)
				//view_body
				view_body.GetBodyCChan().DoShowBody <- 1
			} else {
				panic(errors.New("更新本地包装状态错误！"))
			}
		}
	}
}

//刷新页面 条码 列表;并更新数据库 type=0第一次更新,type=1 非第一次更新
func replaceView_barcode(barcode string, type_s, packnum int, barcodepacking *models.Barcodepacking, barcodepackinglist *models.Barcodepackinglist) {
	if type_s == 0 {
		if pId, err := db_server_mysql.InsertBarcodepacking(barcodepacking); err == nil {
			barcodepackinglist.Packid = pId //第一次插入需要取得id
			if err2 := db_server_mysql.UpdateOtherDataTransaction(barcodepackinglist, packnum); err2 != nil {
				panic(errors.New("更新包装箱列表和包装数量错误！"))
			}
		} else {
			panic(errors.New("插入包装箱信息错误"))
		}

	}
	if type_s == 1 {
		if err2 := db_server_mysql.UpdateOtherDataTransaction(barcodepackinglist, packnum); err2 != nil {
			panic(errors.New("更新包装箱列表和包装数量错误！"))
		}
	}

	view_body.GetHtmlBody().NowPackingNumHTML = strconv.Itoa(packnum)
	view_body.GetHtmlBody().PackingListHTML = `<tr>
			                  <td>` + barcode + `</td>
			                  <td>` + util.GetNowTime("yyyy-MM-dd hh-mm-ss") + `</td>
			                </tr>` + view_body.GetHtmlBody().PackingListHTML

	view_body.GetBodyCChan().DoShowBody <- 1
}

//取得厂区地址
func getAddress_s() string {
	ret_s := "苏州市高新区珠江路521号"
	cangQu := json_conf_get.Getconf().CangQu
	if cangQu == 1 {
		ret_s = "苏州市高新区朝红路505号"
	}
	return ret_s
}
